import { inject, injectable } from "inversify";
import { Event, QuickInput, QuickInputButton, QuickPick, QuickPickItem } from "vscode";
import { IApplicationShell } from "../application/types";

export type InputStep<T extends any> = (input: MultiStepInput<T>, state: T) => Promise<InputStep<T> | void>;

type buttonCallbackType<T extends QuickPickItem> = (quickPick: QuickPick<T>) => void;


type QuickInputButtonSetup = {
    button: QuickInputButton;
    callback: buttonCallbackType<QuickPickItem>;
};

export interface IQuickPickParameters<T extends QuickPickItem, E = any> {
    title?: string;
    step?: number;
    totalSteps?: number;
    canGoBack?: boolean;
    items: T[];
    activeItem?: T;
    placeholder: string;
    customButtonSetup?: QuickInputButtonSetup;
    matchOnDescription?: boolean;
    matchOnDetail?: boolean;
    keepScrollPosition?: boolean;
    sortByLabel?: boolean;
    acceptFilterBoxTextAsSelection?: boolean;
    onChangeItem?: {
        callback: (event: E, quickPick: QuickPick<T>) => void;
        event: Event<E>;
    };
}


type MultiStepInputQuickPicResponseType<T, P> = T | (P extends { buttons: (infer I)[] } ? I : never) | undefined;
type MultiStepInputInputBoxResponseType<P> = string | (P extends { buttons: (infer I)[] } ? I : never) | undefined;

interface InputBoxParameters {
    title: string;
    password?: boolean;
    step?: number;
    totalSteps?: number;
    value: string;
    prompt: string;
    buttons?: QuickInputButton[];
    validate(value: string): Promise<string | undefined>;
}
export interface IMultiStepInput<S> {
    run(start: InputStep<S>, state: S): Promise<void>;
    showQuickPick<T extends QuickPickItem, P extends IQuickPickParameters<T>>({
        title,
        step,
        totalSteps,
        items,
        activeItem,
        placeholder,
        customButtonSetup,
    }: P): Promise<MultiStepInputQuickPicResponseType<T, P>>;
    showInputBox<P extends InputBoxParameters>({
        title,
        step,
        totalSteps,
        value,
        prompt,
        validate,
        buttons,
    }: P): Promise<MultiStepInputInputBoxResponseType<P>>;
}

export class MultiStepInput<S> implements IMultiStepInput<S> {
    private current?: QuickInput;

    private steps: InputStep<S>[] = [];

    constructor(private readonly shell: IApplicationShell) { }
    run(start: InputStep<S>, state: S): Promise<void> {
        throw new Error("128Method not implemented.");
    }
    showQuickPick<T extends QuickPickItem, P extends IQuickPickParameters<T, any>>({ title, step, totalSteps, items, activeItem, placeholder, customButtonSetup, }: P): Promise<MultiStepInputQuickPicResponseType<T, P>> {
        throw new Error("129Method not implemented.");
    }
    showInputBox<P extends InputBoxParameters>({ title, step, totalSteps, value, prompt, validate, buttons, }: P): Promise<MultiStepInputInputBoxResponseType<P>> {
        throw new Error("130Method not implemented.");
    }
}

export const IMultiStepInputFactory = Symbol('IMultiStepInputFactory');
export interface IMultiStepInputFactory {
    create<S>(): IMultiStepInput<S>;
}
@injectable()
export class MultiStepInputFactory {
    constructor(@inject(IApplicationShell) private readonly shell: IApplicationShell) { }

    public create<S>(): IMultiStepInput<S> {
        return new MultiStepInput<S>(this.shell);
    }
}
